package com.icedata.sika.core

import okhttp3.internal.wait
import java.util.*
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.thread
import kotlin.concurrent.write

/**
 * 处理器链
 *
 * 一个挂载T类型处理器的链，处理器接受一个M类型数据返回一个R类型数据
 */
abstract class ProcessorBus<T : Processor<M, R>, M, R>(val sika: Sika) {

    /**
     * 保存的处理器
     */
    protected val processors: LinkedList<T> = LinkedList()

    /**
     * 读写锁
     */
    protected val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()

    /**
     * 挂载一个处理器
     */
    fun mount(processor: T) {
        lock.write {
            if (processors.contains(processor)) {
                sika.throwException(ProcessorsNotUniqueException())
            }
            with(processors) {
                add(processor)
                sortBy { -it.priority }
            }
        }
        processor.onMount(sika)
    }

    fun mountInProcess(processor: T) {
        thread {
            synchronized(lock) {
                lock.wait()
                if (processors.contains(processor)) {
                    sika.throwException(ProcessorsNotUniqueException())
                }
                with(processors) {
                    add(processor)
                    sortBy { -it.priority }
                }
            }
        }
    }

    /**
     * 卸载一个处理器
     */
    fun unmount(processor: T) {
        lock.write {
            processors.remove(processor)
            processor.onUnmount(sika)
        }
    }

    fun unmountInProcess(processor: T) {
        thread {
            synchronized(lock) {
                lock.wait()
                processors.remove(processor)
            }
        }
    }

    /**
     * 广播一条数据
     */
    abstract fun broadcast(data: M)

}

/**
 * 异步处理器链
 */
abstract class AsyncProcessorBus<T : AsyncProcessor<M, R>, M, R>(val sika: Sika) {

    /**
     * 保存的处理器
     */
    protected val processors: LinkedList<T> = LinkedList()

    /**
     * 读写锁
     */
    protected val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()

    /**
     * 挂载一个处理器
     */
    fun mount(processor: T) {
        lock.write {
            if (processors.contains(processor)) {
                sika.throwException(ProcessorsNotUniqueException())
            }
            with(processors) {
                add(processor)
                sortBy { -it.priority }
            }
        }
        processor.onMount(sika)
    }

    fun mountInProcess(processor: T) {
        thread {
            synchronized(lock) {
                lock.wait()
                if (processors.contains(processor)) {
                    sika.throwException(ProcessorsNotUniqueException())
                }
                with(processors) {
                    add(processor)
                    sortBy { -it.priority }
                }
            }
        }
    }

    /**
     * 卸载一个处理器
     */
    fun unmount(processor: T) {
        lock.write {
            processors.remove(processor)
        }
    }

    fun unmountInProcess(processor: T) {
        thread {
            synchronized(lock) {
                lock.wait()
                processors.remove(processor)
            }
        }
    }

    abstract suspend fun broadcast(data: M)

}